承接昨天的練習,今天再來看看Codewars collection這裏的三條題目(第4,5,7題)。整理一下自己的解法之外,也藉此機會學習別人的解法。因為篇幅問題,所以不會貼整條問題,有興趣的朋友可以到連結查看~
Coding Meetup #4 - Higher-Order Functions Series - Find the first Python developer
題目概要:
firstName, country
There will be no Python developers
var list1 = [
{ firstName: 'Mark', lastName: 'G.', country: 'Scotland', continent: 'Europe', age: 22, language: 'JavaScript' },
{ firstName: 'Victoria', lastName: 'T.', country: 'Puerto Rico', continent: 'Americas', age: 30, language: 'Python' },
{ firstName: 'Emma', lastName: 'B.', country: 'Norway', continent: 'Europe', age: 19, language: 'Clojure' }
];
function getFirstPython(list) {
// Thank you for checking out my kata :)
const result = list.filter( ({language}) => language === 'Python')
return result.length > 0 ? `${result[0].firstName}, ${result[0].country}` : `There will be no Python developers`
}
這題難度不高,所以很直覺就用filter
和length
的方法去寫,但submit答案之後又發現一些更合適的寫法。
第1個解法:
function getFirstPython(list) {
const dev = list.find(x => x.language === "Python")
return dev ? `${dev.firstName}, ${dev.country}` : "There will be no Python developers"
}
突然發現自己竟然沒有想到用find
的方法!因為題目要求只找出第一個寫Python的開發者就可以了,所以這裏非常適合用find
!
第2個解法:
const getFirstPython = list =>
(val => val ? `${val.firstName}, ${val.country}` : `There will be no Python developers`)
(list.find(val => val.language === `Python`));
這個解法我看了幾次都看不懂,之後看看原作者在他的答案下的comment,提到立即函式(IIFE)的MDN連結,我才明白他在用立即函式的方法簡寫第一個解法。他把用find
找出來的結果當作参數,傳進立即函式裏面去做判斷。
第3個解法:
function getFirstPython(list) {
// Thank you for checking out my kata :)
const result = list.filter( ({language}) => language === 'Python')[0]
return result ? `${result.firstName}, ${result.country}` : `There will be no Python developers`
}
這個解法是我看完另一個網友的寫法,再去簡寫我的寫法。直接在filter
建立的陣列裏指定第一個元素,之後拿它去做判斷。如果根本沒有Python開發者的話,result會是undefined
,undefined
是falsy,這便會回傳沒有Python開發者的那句字串。這樣就不用拿length > 0
去做比對了。
Coding Meetup #5 - Higher-Order Functions Series - Prepare the count of languages
題目概要:回傳一個物件,裏面會顯示有多少個開發者在用某個程式語言。
例如這堆資料中:
var list1 = [
{ firstName: 'Noah', lastName: 'M.', country: 'Switzerland', continent: 'Europe', age: 19, language: 'C' },
{ firstName: 'Anna', lastName: 'R.', country: 'Liechtenstein', continent: 'Europe', age: 52, language: 'JavaScript' },
{ firstName: 'Ramon', lastName: 'R.', country: 'Paraguay', continent: 'Americas', age: 29, language: 'Ruby' },
{ firstName: 'George', lastName: 'B.', country: 'England', continent: 'Europe', age: 81, language: 'C' },
];
這裏要回傳:
{ C: 2, JavaScript: 1, Ruby: 1 }
function countLanguages(list) {
// thank you for checking out the Coding Meetup kata :)
//建立一個放著全部開發者寫的程式語言的陣列
const allList = list.map( (dev) => dev.language)
//建立一個程式語言不重覆的陣列
const uniqueList = allList.filter( (dev,index)=> allList.indexOf(dev) === index)
const obj = {}
//建立一個物件:{uniqueList的元素 : 以目前uniqueList裏被迭代的語言為篩選條件,找尋在allList陣列中與篩選條件相同的語言,放列一個陣列裏,並求它的長度}
for(i=0; i<uniqueList.length; i++){
obj[uniqueList[i]] = allList.filter( (language) => language === uniqueList[i]).length
}
return obj
}
這題自己的確花了點時間去想,簡單講我的思路就是建立兩個陣列,一個是有重覆元素的陣列(allList),一個是不重覆元素的陣列(uniqueList)。在uniqueList陣列裏的所有元素,就是obj
所有的鍵(key)。
而這些鍵對應的值(value)呢?在每一次跑uniqueList的元素時,該元素會成為篩選條件,讓我在allList裏找出與篩選條件一樣的程式語言,並放到一個新陣列裏。例如跑到"C"時,因為有2個開發者寫C,所以會得出["C","C"]這個陣列,跑到"JavaScript"時,會得出["JavaScript"],如此類推。而這些陣列的length,就代表人數,也就是鍵對應的值。
但自己這樣寫真的是太累贅了,還是看看別人的解法來學習吧。
第1個解法:
function countLanguages(list){
const count = {}
list.forEach( (dev)=> count[dev.language] = (count[dev.language] || 0)+1)
return count
}
一開始看不懂,看懂之後就不得了~~ 果然是最佳解答!在forEach
函式裏,先判斷count
物件裏面有沒有該程式語言的屬性,如沒有,就預設是0,之後再+1,例如第一次跑forEach時,就會變成{C:(0+1)}
,在跑最後一次時,就會變成{C:(1+1)}
。
第2個解法:
function countLanguages(list) {
var r = {};
list.forEach(x => {
let p = [x.language];
r.hasOwnProperty(p) ? r[p] ++ : r[p] = 1;
});
return r;
}
這裏的解法與第1個解法的思路很相似,差異是這裏用hasOwnProperty()
的方法,而非短路求值||
的方法,去檢查物件裏是否已經有某個程式語言屬性,以及設定預設值。如果已有屬性,就在該屬性值+1,如無,就預設值為1。
Coding Meetup #7 - Higher-Order Functions Series - Find the most senior developer
題目6比較答案比較直接,而且大家答法都很相似,所以就直接跳到討論題目7~
題目概要:回傳一個陣列,裏面放有年紀最大的開發者資料,如年齡相同,則按原本陣列的顯示次序來顯示。
例如以下這堆資料:
var list1 = [
{ firstName: 'Gabriel', lastName: 'X.', country: 'Monaco', continent: 'Europe', age: 49, language: 'PHP' },
{ firstName: 'Odval', lastName: 'F.', country: 'Mongolia', continent: 'Asia', age: 38, language: 'Python' },
{ firstName: 'Emilija', lastName: 'S.', country: 'Lithuania', continent: 'Europe', age: 19, language: 'Python' },
{ firstName: 'Sou', lastName: 'B.', country: 'Japan', continent: 'Asia', age: 49, language: 'PHP' },
];
我要回傳的結果是:
[
{ firstName: 'Gabriel', lastName: 'X.', country: 'Monaco', continent: 'Europe', age: 49, language: 'PHP' },
{ firstName: 'Sou', lastName: 'B.', country: 'Japan', continent: 'Asia', age: 49, language: 'PHP' },
]
function findSenior(list) {
// thank you for checking out the Coding Meetup kata :)
const oldest = list.reduce( (a,b) => a.age >= b.age ? a : b);
return list.filter( dev => dev.age === oldest.age)
}
這題其實都比較簡單,要找出年紀最大的開發者,意思就是找出age
屬性值最大的物件。這裏我用reduce
的方法,比對每個物件的age
屬性值,如果找到較大的值,就返回那一個物件,並在下一次比較時,用那一個物件的age
屬性與目前被迭代的物件的age
屬性比較,整個reduce
函式最後會回傳age
屬性值最大的物件。之後再用filter
方法建立陣列,放有與最大年紀相同的物件。
function findSenior(list) {
var maxAge = Math.max(...list.map(person => person.age));
return list.filter(person => person.age === maxAge);
}
看完這個解法後,突然又想起自己忘記了Math.max
這個超級好用的方法!先用map
的函式,集合所有age
屬性值在一個陣列裏,用展開運算子攤開所有在陣列中的數字,之後再用Math.max
的方法找出最大數字。最後的做法就如我的解法一樣了。
雖然有些寫法好像真的比較簡潔,但個人覺得過於追求簡潔性時也可能會降低了程式碼的可讀性(?),使之後除錯時會更困難。除此之外,在刷題的過程中,看到別人的解法,除了比較哪個寫得最短之外,也需要思考一下別人的思路,以及他的思路與自己的思路的相異之處,希望這樣的訓練會使自己更懂得靈活去做不同方法,也更懂得了解別人的程式碼。